プログラマ -

プログラマ -

The Shadows Unveiled: eBPF - Manipulating the Kernel's Secret Symphony

Hacking

Introduction

In the shadowy world of Linux kernel manipulation, a game-changing tool emerged in 2016, ushering in a new era of control and surveillance: eBPF, or Extended Berkeley Packet Filter. This nifty piece of tech allows developers to engage with the Linux kernel directly through what we call eBPF programs, encoded in bytecode form. Given its portability, these programs are compiled on the fly using Just-In-Time (JIT) compilation and executed seamlessly within the kernel via the BPF virtual machine.

The Enigmatic BPF VM

But before we embark on a journey into the clandestine universe of eBPF programs, let’s first uncover the enigmatic infrastructure that permits their execution within the kernel. It’s a 64-bit virtual machine, founded on the bedrock of a Reduced Instruction Set Computing (RISC) architecture, replete with its own set of registers.

RISC architecture, for the uninitiated, implies a streamlined instruction set compared to the more cumbersome Complex Instruction Set Computing (CISC) architecture. While some CPUs employ CISC instructions, emulated by RISC, others unabashedly embrace the purity of RISC or CISC. For instance, Apple’s A6 chip and NVIDIA’s Tegra 3 bask in the glory of ARM’s RISC Cortex-A9 processor.

As I alluded to earlier, this virtual machine empowers the execution of BPF programs directly within the kernel’s hallowed precincts, granting them a VIP pass to a select subset of kernel functions and a piece of the memory pie. Crucially, it’s vital to grasp that this isn’t some run-of-the-mill virtual machine; it’s a full-fledged virtual powerhouse intricately integrated into the kernel’s core. Don’t confuse it with kernel-based virtual machines like KVM, which necessitate third-party kernel modules to oversee virtual mayhem.

The Grand Question: Why eBPF?

You might be tempted to ask, “Why the need for eBPF programs when everything they do could theoretically be accomplished through kernel modules?” A fair question, indeed.

Developing kernel modules is a perilous endeavor, one that demands unwavering diligence. As history has demonstrated, and as we continue to witness in the present, vulnerabilities exploited via these modules cast a long, dark shadow over the kernel’s security.

Consider, for a moment, the specter of a buffer overflow vulnerability lurking within a module’s code. In this nightmare scenario, an attacker could potentially elevate their program’s status to that of a root entity by resetting task credentials. This holds true even in the face of formidable security fortifications like kernel ASLR (Address Space Layout Randomization), execution and access modes, and more.

Within the labyrinthine corridors of the Linux kernel, program execution is symbolized by a “task.” With kernel functions dancing to their own tune, they can elevate a task’s privileges to the coveted realm of UID and GID 0, courtesy of functions like prepare_kernel_cred(0) and commit_creds.

An eBPF program, on the other hand, emerges as a beacon of security. It is inherently bound by the shackles of finite execution, lacking the capriciousness of Turing completeness. Loops are conspicuously absent from its arsenal, compelling the program to conclude its operations gracefully. Execution takes on an entirely different form, harnessing the power of event hooks injected directly by the kernel into the heart of the matter. Moreover, since eBPF programs exist in the realm of bytecode, the eBPF VM herself meticulously scrutinizes the program before the execution drumbeat commences.

BPF Programs: Unveiling the Arsenal

Let us now illuminate the clandestine arsenal of BPF programs, a trove divided into two distinct categories: tracing and networking.

Tracing:

In this clandestine realm, you wield programs that unfurl the inner workings of your system, casting a revealing light on the cryptic kernel and the mysteries of your hardware. These programs possess the uncanny ability to pry open the memory vaults of processes, extracting traces of esoteric operations, and gaining unfettered access to resources like file descriptors, memory domains, and CPU esoterica.

Networking:

As the moniker suggests, this category bestows the power to forge connections with the ethereal realm of networking. Picture this: you can attach a BPF program to various states of existence, such as glimpsing a packet before it succumbs to the siren call of the network driver, or latching onto a BPF program just before it transcends into the hallowed halls of user space. Possibilities abound.

incredible meme

Types of BPF Programs

Now, let’s delve into the various types of BPF programs, each harboring its own unique purpose, hidden away like ancient scrolls of arcane knowledge.

Socket Filter

This clandestine enabler grants access to all packets traversing the byzantine pathways of a socket. However, it’s worth noting that this type of program doesn’t bestow upon you the power to tamper with the packet’s contents or alter its ultimate destiny.

Inscribed in the annals of code as the constant: BPF_PROG_TYPE_SOCKET_FILTER

Kprobe

Behold, the Kprobe—a program capable of erecting probes (dynamic breakpoints) within the sacred rituals of kernel land.

As decreed by the constant: BPF_PROG_TYPE_KPROBE

XDP

XDP programs allow you to exert influence on the network at the inception of its journey, long before it embarks on its convoluted voyage through the driver’s labyrinthine corridors. These programs wield various returns, from XDP_PASS to XDP_DROP, and more. The allure of this program type is tantalizingly immense, and we might dedicate a future tome to its exploration.

Enshrined within the code as the constant: BPF_PROG_TYPE_XDP

These are but a glimpse into the myriad program types, including those designed to interface with cgroups, kernel performance events, and tracepoints. A comprehensive compendium awaits your perusal at https://lwn.net/Articles/740157.

The Unassailable BPF Verifier

The audacious act of executing code within the sacred sanctum of the kernel might appear recklessly bold at first glance. The stakes are undoubtedly high in production systems. Yet, the taming of this digital tempest owes much to a formidable guardian—the BPF verifier.

The BPF verifier embarks on a noble quest: to ensure your program conforms to the sacred rites of the BPF VM and adheres to the tenets of security. This vigilant protector employs a multi-stage process, commencing with the transformation of your code into an intricate acyclic graph, a labyrinth of nodes, each representing an instruction, interlinked in a symphony of execution.

Once the graphical tapestry of your code is unfurled, the verifier embarks on a journey of discovery within this enigmatic graph. It seeks out forbidden code—recursions, infinite loops, size breaches (lest it surpass the hallowed limit of 4096), the echoes of dead code, and access verifications.

The final crucible arrives—a test that subjects your code to its first tentative steps in a sandboxed environment. It scrutinizes each instruction for validity, ensuring all pointers are

accessible and referenceable. Only after your program reaches its denouement (BPF_EXIT) does the verifier signal its approval of a successful performance.

A curious tidbit: You can infuse additional attributes into the bpf syscall to glean insights into the scrutiny your program endures.

In Denouement

As we conclude this foray into the labyrinthine world of eBPF, I refrain from plunging into the depths of BTF or tail calls. Those chapters of arcane wisdom shall unfurl in future tomes. Even introductions must heed the wisdom of restraint.

Nonetheless, before we part ways, a smattering of definitions:

  • BTF (BPF Type Format): A cipher that enhances the legibility of debug information for your programs.

  • BPF Tail Calls: A clandestine art allowing you to summon other BPF programs, a potent means to transcend the confines of the maximum size limit (4096), as instructions continue their dance in another program—a cascade of boundless potential (4096 *2).

Fare thee well, and may your eBPF journeys be as enigmatic as they are enlightening. A+,